ci: add environment: production to publish and build-image jobs#490
ci: add environment: production to publish and build-image jobs#490hermes-exosphere wants to merge 1 commit into
Conversation
Adds to: - publish.yml (publish → npm registry) - build-image.yml (build → GHCR push) This enables approval gates via GitHub Environments on all artifact releases including npm publishing and GHCR image pushes.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughBoth the image build and package publish GitHub Actions jobs now target the ChangesProduction environment assignments
Estimated code review effort: 1 (Trivial) | ~2 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
🔍 Automated code review started — analyzing [{"additions":1,"deletions":0,"path":".github/workflows/build-image.yml"},{"additions":1,"deletions":0,"path":".github/workflows/publish.yml"}] files, +2/-0... ⏱️ This may take a few minutes. Results will be posted here when complete. |
| jobs: | ||
| publish: | ||
| runs-on: ubuntu-latest | ||
| environment: production |
There was a problem hiding this comment.
🟡 Verify the production environment's deployment-branch policy allows tag refs — otherwise this blocks every release.
This job is triggered by release: published, so it runs on a tag ref (github.ref = refs/tags/<tag>), not a branch. GitHub Environments evaluate Deployment branches and tags against that ref. If you configure production with "Selected branches" — the intuitive way to "restrict production to main" — this publish job is rejected on every release (a tag is not a branch):
Tag
<tag>is not allowed to deploy to production due to environment protection rules.
When configuring the environment:
- Use "Selected branches and tags" and add a tag rule (e.g.
v*), or - Leave "No restriction" on deployment branches and rely on required-reviewers instead.
Two more job-specific notes:
- npm provenance identity changes. With
environment: productionset, the OIDC token'ssubclaim becomesrepo:FailproofAI/failproofai:environment:production(instead of…:ref:refs/tags/…). Token auth viaNODE_AUTH_TOKENis unaffected, but the--provenanceattestation (line 93) records this new builder identity. Harmless today; but if you ever adopt npm trusted publishing (OIDC), the environment name must be registered on the npm side. - Approval widens the race window on the final
git push origin main. This job's last step (lines 102–117) commits the next-dev-version bump directly tomain, and there is noconcurrency:group. An approval gate delays execution, so two releases approved close together could race / double-bumpmain. Considerconcurrency: { group: publish, cancel-in-progress: false }if you enable a wait timer or reviewers.
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| environment: production |
There was a problem hiding this comment.
🟠 A required-reviewer gate here will stall the daily unattended rebuild — the highest-impact caveat of this PR.
This workflow is explicitly designed to run unattended on a schedule. From this file's own header:
The daily rebuild refreshes the
@latest-pinned claude-code + failproofai npm globals.
schedule:
- cron: '0 8 * * *' # daily at 08:00 UTCOnce the production environment has required reviewers — the stated intent of this PR — every trigger (this cron and push to main) creates a pending deployment that waits for a human. The nightly run will:
- sit unapproved (nobody is watching at 08:00 UTC), then
- be auto-cancelled after ~30 days, and
- pile up as a rolling backlog of pending deployments.
Net effect: the automation this container exists for silently stops running.
Secondary issue — build-only validation is gated too. workflow_dispatch exposes push_to_ghcr: false ("validate the Dockerfile without publishing"). Because the gate sits at the job level, even a no-publish validation run now needs production approval, despite releasing nothing.
Options (pick per intent):
- Gate only actual manual pushes — make the environment conditional so scheduled/push runs skip it:
An empty environment name = no gate, so the nightly refresh stays unattended while manual publishes are gated. (Tradeoff: nightly pushes then bypass the gate — acceptable only if nightly
environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.push_to_ghcr) && 'production' || '' }}
@latestrefreshes aren't what you want a human to approve.) - Split build vs. push into two jobs and gate only the push job.
- Use a wait timer / branch policy rather than required reviewers for this workflow, so the cron proceeds after the timer instead of blocking indefinitely.
If the intent genuinely is "a human approves every image push, nightly included," this is working as designed — but that contradicts the header's "daily rebuild" purpose, so please confirm.
🔍 Automated Code Review📋 Executive SummaryThis PR adds 📊 Change Architecturegraph TD
subgraph P["publish.yml"]
R["release: published<br/>(tag ref)"] --> PJ["publish job"]
WD1["workflow_dispatch"] --> PJ
PJ -->|"NEW: environment: production"| G1{"prod gate"}
G1 --> NPM["npm publish --provenance"]
G1 --> BUMP["git push origin main<br/>(version bump)"]
end
subgraph B["build-image.yml"]
CRON["schedule: daily 08:00 UTC"] --> BJ["build job"]
PU["push: main (paths)"] --> BJ
WD2["workflow_dispatch<br/>push_to_ghcr"] --> BJ
BJ -->|"NEW: environment: production"| G2{"prod gate"}
G2 --> GHCR["push image → GHCR"]
end
style G1 fill:#FFD700
style G2 fill:#FFA500
style CRON fill:#FF9999
style R fill:#FFD700
Legend: 🟢 New · 🔵 Modified · 🟡 Breaking-change risk (config-dependent) · 🟠 High-impact caveat · 🔴 Trigger that conflicts with gating 🔴 Breaking ChangesNo breaking change in the diff itself — but two configuration-dependent breakages become possible the moment the intended protection rules are switched on:
Neither can be fixed in this diff — they're guidance for when the
|
hermes-exosphere
left a comment
There was a problem hiding this comment.
Automated review — posting as a comment (not request-changes): the 2-line diff is correct and safe to merge as-is. 🟡
The substantive risks are not in the diff — they surface once the production environment's protection rules are configured server-side, which is this PR's stated intent. Two are worth acting on before you flip those rules on:
- 🟠
build-image.yml— a required-reviewer gate stalls the unattended daily cron (0 8 * * *) the workflow exists for; it also gatespush_to_ghcr: falsevalidation runs that release nothing. - 🟡
publish.yml— the job runs on a tag ref, so an environment "Selected branches" policy would reject every release; use "Selected branches and tags" (v*) or "No restriction".
Also: CHANGELOG.md isn't updated (repo convention requires an entry per PR; package.json is at 0.0.13-beta.3 with no matching section).
See inline comments + the summary for details, options, and evidence.
Summary
Adds
environment: productionto both artifact-releasing workflows to enable approval gates via GitHub Environments.Changes
environment: productionto thepublishjob (npm registry publish)environment: productionto thebuildjob (GHCR image push)Why
Both jobs release artifacts — the npm package and the hook-sync container image. Adding
environment: productionenables the GitHub Environments protection rules (required reviewers, wait timer, etc.) to gate these releases.Summary by CodeRabbit